package com.yangjun.common.excel;

import java.io.InputStream;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.common.collect.Maps;
import com.yangjun.utils.ReflectUtil;

/**
 * @ClassName XMLExcelDefinitionReader
 * @Description Excel 自定义XML读取注册
 * @author Administrator
 * @Date 2017年6月13日 下午5:30:19
 * @version 1.0.0
 */
public class XMLExcelDefinitionReader implements ExcelDefinitionReader{
	
	/** 
	 * 注册信息
	 */
	private Map<String, ExcelDefinition> registry;
	/**
	 * 配置文件的路径
	 */
	private String location;
	
	public XMLExcelDefinitionReader(String location) {
		this.location = location;
		registry = Maps.newHashMap();
		Resource resource = new ClassPathResource(location);
		try {
			loadExcelDefinitions(resource.getInputStream());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 加载解析配置文件信息
	 * @param inputStream
	 * @throws Exception
	 */
	protected void loadExcelDefinitions(InputStream inputStream) throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = factory.newDocumentBuilder();
		Document doc = docBuilder.parse(inputStream);
		registerExcelDefinitions(doc);
		inputStream.close();//注册完关闭流
	}
	/**
	 * @Description 注册Excel定义信息
	 * @param doc
	 * @author yangjun
	 * @Date 2017年6月13日 下午5:53:32
	 */
	protected void registerExcelDefinitions(Document doc){
		Element root = doc.getDocumentElement();
		NodeList nl = root.getChildNodes();
		for(int i = 0,len=nl.getLength();i<len;i++){
			Node node = nl.item(i);
			if(node instanceof Element){
				Element ele = (Element)node;
				processExcelDefinition(ele);
			}
		}
	}
	/**
	 * 
	 * @Description 解析和校验Excel定义,处理每个excel标签内容
	 * @param ele
	 * @author yangjun
	 * @Date 2017年6月13日 下午6:23:29
	 */
	protected void processExcelDefinition(Element ele){
		ExcelDefinition excelDefinition = new ExcelDefinition();
		//设置id
		String id = ele.getAttribute("id");
		if(StringUtils.isBlank(id)){
			throw new ExcelException("Excel 配置文件[" + location + "], id为 [ null ] ");
		}
		if(registry.containsKey(id)){
			throw new ExcelException("Excel 配置文件[" + location + "], id为 [ "+id+" ] 的模板不止一个");
		}
		excelDefinition.setId(id);
		//设置class
		String className = ele.getAttribute("class");
		if(StringUtils.isBlank(className)){
			throw new ExcelException("Excel 配置文件[" + location + "], id为 [ "+id+" ] 的 class 为 [ null ]");
		}
		Class<?> clazz = null;
		try {
			clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		excelDefinition.setClassName(className);
		excelDefinition.setClazz(clazz);
		//设置列宽
		if(StringUtils.isNotBlank(ele.getAttribute("defaultColumnWidth"))){
			try{
				excelDefinition.setDefaultColumnWidth(Integer.valueOf(ele.getAttribute("defaultColumnWidth")));
			}catch(NumberFormatException e){
				throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
				+ " ] 的 defaultColumnWidth 属性不能为 [ "+ele.getAttribute("defaultColumnWidth")+" ],只能为int类型");
			}
		}
		//设置sheetName
		if(StringUtils.isNotBlank(ele.getAttribute("sheetname"))){
			excelDefinition.setSheetname(ele.getAttribute("sheetname"));
		}
		//设置样式是否开启
		if(StringUtils.isNotBlank(ele.getAttribute("enableStyle"))){
			excelDefinition.setEnableStyle(Boolean.parseBoolean(ele.getAttribute("enableStyle")));
		}
		//设置对齐方式
		if(StringUtils.isNotBlank(ele.getAttribute("defaultAlign"))){
			try{
			excelDefinition.setDefaultAlign(HorizontalAlignment.CENTER);
			}catch(Exception e){
				throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
				+ " ] 的 defaultAlign 属性不能为 [ "+ele.getAttribute("defaultAlign")+" ],目前支持的left,center,right");
			}
		}
		//设置sheet index
		if(StringUtils.isNotBlank(ele.getAttribute("sheetIndex"))){
			try{
				int sheetIndex = Integer.parseInt(ele.getAttribute("sheetIndex"));
				if(sheetIndex<0){
					throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
					+ " ] 的 sheetIndex 属性不能为 [ "+ele.getAttribute("sheetIndex")+" ],索引位置至少从0开始");
				}
				excelDefinition.setSheetIndex(sheetIndex);
			}catch(NumberFormatException e){
				throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
				+ " ] 的 sheetIndex 属性不能为 [ "+ele.getAttribute("sheetIndex")+" ],只能为int类型");
			}

		}
		//处理每个excel节点下的field节点
		processField(ele,excelDefinition);
		//注册每个定义的excel模板
		registry.put(id, excelDefinition);
	}
	/**
	 * 
	 * @Description 解析和校验Excel定义,处理每个field标签内容
	 * @param ele
	 * @author yangjun
	 * @Date 2017年6月13日 下午6:23:29
	 */
	protected void processField(Element ele, ExcelDefinition excelDefinition) {
		//excel标签下的所有field
		NodeList fieldNode = ele.getElementsByTagName("field");
		if(fieldNode != null){
			for(int i=0,len=fieldNode.getLength();i<len;i++){
				Node node = fieldNode.item(i);
				if(node instanceof Element){
					FieldValue fieldValue = new FieldValue();
					Element fieldEle = (Element)node;
					//设置name
					String name = fieldEle.getAttribute("name");
					if(StringUtils.isBlank(name)){
						throw new ExcelException("Excel 配置文件[" + location + "], id为 [ "+excelDefinition.getId()+" ] 的 name 属性不能为 [ null ]");
					}
					fieldValue.setName(name);
					
					//设置title
					String title = fieldEle.getAttribute("title");
					if(StringUtils.isBlank(title)){
						throw new ExcelException("Excel 配置文件[" + location + "], id为 [ "+excelDefinition.getId()+" ] 的 title 属性不能为 [ null ]");
					}
					fieldValue.setTitle(title);
					
					String pattern = fieldEle.getAttribute("pattern");
					if(StringUtils.isNotBlank(pattern)){
						fieldValue.setPattern(pattern);
					}
					String format = fieldEle.getAttribute("format");
					if(StringUtils.isNotBlank(format)){
						fieldValue.setFormat(format);
					}
					String isNull = fieldEle.getAttribute("isNull");
					if(StringUtils.isNotBlank(isNull)){
						fieldValue.setNull(Boolean.parseBoolean(isNull));
					}
					String regex = fieldEle.getAttribute("regex");
					if(StringUtils.isNotBlank(regex)){
						fieldValue.setRegex(regex);
					}
					String regexErrMsg = fieldEle.getAttribute("regexErrMsg");
					if(StringUtils.isNotBlank(regexErrMsg)){
						fieldValue.setRegexErrMsg(regexErrMsg);
					}
					//设置对齐方式
					String align = fieldEle.getAttribute("align");
					if(StringUtils.isNotBlank(align)){
						try{
							//获取cell对齐方式的常量值
							short constValue = ReflectUtil.getConstValue(CellStyle.class, "ALIGN_"+align.toUpperCase());
							fieldValue.setAlign(constValue);
						}catch(Exception e){
							throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
							+ " ] 的 align 属性不能为 [ "+align+" ],目前支持的left,center,right");
						}
					}
					
					//cell 宽度
					String columnWidth = fieldEle.getAttribute("columnWidth");
					if(StringUtils.isNotBlank(columnWidth)){
						try{
							int intVal = Integer.parseInt(columnWidth);
							fieldValue.setColumnWidth(intVal);
						}catch(NumberFormatException e){
							throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
							+ " ] 的 columnWidth 属性 [ "+columnWidth+" ] 不是一个合法的数值");
						}
					}
					//cell标题背景色
					String titleBgColor = fieldEle.getAttribute("titleBgColor");
					if(StringUtils.isNotBlank(titleBgColor)){
						try{
							//获取cell对齐方式的常量值
							IndexedColors color = ReflectUtil.getConstValue(IndexedColors.class,titleBgColor.toUpperCase());
							fieldValue.setTitleBgColor(color.index);
						}catch(Exception e){
							throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
							+ " ] 的 titleBgColor 属性不能为 [ "+titleBgColor+" ],具体看[org.apache.poi.ss.usermodel.IndexedColors]支持的颜色");
						}
					}
					//cell标题字体颜色
					String titleFountColor = fieldEle.getAttribute("titleFountColor");
					if(StringUtils.isNotBlank(titleFountColor)){
						try{
							//获取cell对齐方式的常量值
							IndexedColors color = ReflectUtil.getConstValue(IndexedColors.class,titleFountColor.toUpperCase());
							if(color==null){
								throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
								+ " ] 的 titleFountColor 属性不能为 [ "+titleFountColor+" ],具体看[org.apache.poi.ss.usermodel.IndexedColors]支持的颜色");
							}
							fieldValue.setTitleFountColor(color.index);
						}catch(Exception e){
							throw new ExcelException(e);
						}
					}
					
					//roundingMode 解析
					String roundingMode = fieldEle.getAttribute("roundingMode");
					if(StringUtils.isNotBlank(roundingMode)){
						try{
							//获取roundingMode常量值
							RoundingMode mode =  ReflectUtil.getConstValue(RoundingMode.class,roundingMode.toUpperCase());
							if(mode == null){
								throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
								+ " ] 的 roundingMode 属性不能为 [ "+roundingMode+" ],具体看[java.math.RoundingMode]支持的值");
							}
							fieldValue.setRoundingMode(mode);
						}catch(Exception e){
							throw new ExcelException(e);
						}
					}
					
					//解析decimalFormat
					String decimalFormatPattern = fieldEle.getAttribute("decimalFormatPattern");
					if(StringUtils.isNotBlank(decimalFormatPattern)){
						try{
							fieldValue.setDecimalFormatPattern(decimalFormatPattern);
							fieldValue.setDecimalFormat(new DecimalFormat(decimalFormatPattern));
							fieldValue.getDecimalFormat().setRoundingMode(fieldValue.getRoundingMode());
						}catch(Exception e){
							throw new ExcelException("Excel 配置文件[" + location + "] , id为 [ " + excelDefinition.getId()
							+ " ] 的 decimalFormatPattern 属性不能为 [ "+decimalFormatPattern+" ],请配置标准的JAVA格式");
						}
					}
					
					//解析,值为空时,字段的默认值
					String defaultValue = fieldEle.getAttribute("defaultValue");
					if(StringUtils.isNotBlank(defaultValue)){
						fieldValue.setDefaultValue(defaultValue);
					}
					
					excelDefinition.getFieldValues().add(fieldValue);
				}
			}
		}
	}
	/**
	 * @return 不可被修改的注册信息
	 */
	@Override
	public Map<String, ExcelDefinition> getRegistry() {
        // 不能put remove 操作但可以对里的对象进行操作
		return Collections.unmodifiableMap(registry);
	}
	
	
}
